* Bit width of the DMA heap.
*/
static unsigned int dma_bitsize = CONFIG_DMA_BITSIZE;
-static unsigned long max_dma_mfn = (1UL << (CONFIG_DMA_BITSIZE - PAGE_SHIFT)) - 1;
+static unsigned long max_dma_mfn = (1UL<<(CONFIG_DMA_BITSIZE-PAGE_SHIFT))-1;
static void parse_dma_bits(char *s)
{
unsigned int v = simple_strtol(s, NULL, 0);
unsigned int i, j, zone;
unsigned int node = cpu_to_node(cpu), num_nodes = num_online_nodes();
unsigned long request = 1UL << order;
+ cpumask_t extra_cpus_mask, mask;
struct page_info *pg;
ASSERT(node >= 0);
spin_unlock(&heap_lock);
+ cpus_clear(mask);
+
+ for ( i = 0; i < (1 << order); i++ )
+ {
+ /* Reference count must continuously be zero for free pages. */
+ BUG_ON(pg[i].count_info != 0);
+
+ /* Add in any extra CPUs that need flushing because of this page. */
+ cpus_andnot(extra_cpus_mask, pg[i].u.free.cpumask, mask);
+ tlbflush_filter(extra_cpus_mask, pg[i].tlbflush_timestamp);
+ cpus_or(mask, mask, extra_cpus_mask);
+
+ /* Initialise fields which have other uses for free pages. */
+ pg[i].u.inuse.type_info = 0;
+ page_set_owner(&pg[i], NULL);
+ }
+
+ if ( unlikely(!cpus_empty(mask)) )
+ {
+ perfc_incrc(need_flush_tlb_flush);
+ flush_tlb_mask(mask);
+ }
+
return pg;
}
unsigned int zone, struct page_info *pg, unsigned int order)
{
unsigned long mask;
- unsigned int node = phys_to_nid(page_to_maddr(pg));
+ unsigned int i, node = phys_to_nid(page_to_maddr(pg));
+ struct domain *d;
ASSERT(zone < NR_ZONES);
ASSERT(order <= MAX_ORDER);
ASSERT(node >= 0);
ASSERT(node < num_online_nodes());
+ for ( i = 0; i < (1 << order); i++ )
+ {
+ BUG_ON(pg[i].count_info != 0);
+ if ( (d = page_get_owner(&pg[i])) != NULL )
+ {
+ pg[i].tlbflush_timestamp = tlbflush_current_time();
+ pg[i].u.free.cpumask = d->domain_dirty_cpumask;
+ }
+ else
+ {
+ cpus_clear(pg[i].u.free.cpumask);
+ }
+ }
+
spin_lock(&heap_lock);
map_free(page_to_mfn(pg), 1 << order);
/*
* Scrub all unallocated pages in all heap zones. This function is more
* convoluted than appears necessary because we do not want to continuously
- * hold the lock or disable interrupts while scrubbing very large memory areas.
+ * hold the lock while scrubbing very large memory areas.
*/
void scrub_heap_pages(void)
{
if ( (mfn % ((100*1024*1024)/PAGE_SIZE)) == 0 )
printk(".");
- spin_lock_irq(&heap_lock);
+ spin_lock(&heap_lock);
/* Re-check page status with lock held. */
if ( !allocated_in_map(mfn) )
}
}
- spin_unlock_irq(&heap_lock);
+ spin_unlock(&heap_lock);
}
printk("done.\n");
void init_xenheap_pages(paddr_t ps, paddr_t pe)
{
- unsigned long flags;
-
ps = round_pgup(ps);
pe = round_pgdown(pe);
if ( pe <= ps )
if ( !IS_XEN_HEAP_FRAME(maddr_to_page(pe)) )
pe -= PAGE_SIZE;
- local_irq_save(flags);
init_heap_pages(MEMZONE_XEN, maddr_to_page(ps), (pe - ps) >> PAGE_SHIFT);
- local_irq_restore(flags);
}
void *alloc_xenheap_pages(unsigned int order)
{
- unsigned long flags;
struct page_info *pg;
- int i;
- local_irq_save(flags);
- pg = alloc_heap_pages(MEMZONE_XEN, MEMZONE_XEN, smp_processor_id(), order);
- local_irq_restore(flags);
+ ASSERT(!in_irq());
+ pg = alloc_heap_pages(MEMZONE_XEN, MEMZONE_XEN, smp_processor_id(), order);
if ( unlikely(pg == NULL) )
goto no_memory;
memguard_unguard_range(page_to_virt(pg), 1 << (order + PAGE_SHIFT));
- for ( i = 0; i < (1 << order); i++ )
- {
- pg[i].count_info = 0;
- pg[i].u.inuse._domain = 0;
- pg[i].u.inuse.type_info = 0;
- }
-
return page_to_virt(pg);
no_memory:
void free_xenheap_pages(void *v, unsigned int order)
{
- unsigned long flags;
+ ASSERT(!in_irq());
if ( v == NULL )
return;
- memguard_guard_range(v, 1 << (order + PAGE_SHIFT));
+ memguard_guard_range(v, 1 << (order + PAGE_SHIFT));
- local_irq_save(flags);
free_heap_pages(MEMZONE_XEN, virt_to_page(v), order);
- local_irq_restore(flags);
}
unsigned int memflags)
{
struct page_info *pg = NULL;
- cpumask_t mask;
- unsigned long i;
unsigned int bits = memflags >> _MEMF_bits, zone_hi = NR_ZONES - 1;
ASSERT(!in_irq());
return NULL;
}
- if ( pg == NULL )
- if ( (pg = alloc_heap_pages(MEMZONE_XEN + 1,
- zone_hi,
- cpu, order)) == NULL )
- return NULL;
-
- mask = pg->u.free.cpumask;
- tlbflush_filter(mask, pg->tlbflush_timestamp);
-
- pg->count_info = 0;
- pg->u.inuse._domain = 0;
- pg->u.inuse.type_info = 0;
-
- for ( i = 1; i < (1 << order); i++ )
- {
- /* Add in any extra CPUs that need flushing because of this page. */
- cpumask_t extra_cpus_mask;
- cpus_andnot(extra_cpus_mask, pg[i].u.free.cpumask, mask);
- tlbflush_filter(extra_cpus_mask, pg[i].tlbflush_timestamp);
- cpus_or(mask, mask, extra_cpus_mask);
-
- pg[i].count_info = 0;
- pg[i].u.inuse._domain = 0;
- pg[i].u.inuse.type_info = 0;
- page_set_owner(&pg[i], NULL);
- }
-
- if ( unlikely(!cpus_empty(mask)) )
- {
- perfc_incrc(need_flush_tlb_flush);
- flush_tlb_mask(mask);
- }
+ if ( (pg == NULL) &&
+ ((pg = alloc_heap_pages(MEMZONE_XEN + 1, zone_hi,
+ cpu, order)) == NULL) )
+ return NULL;
if ( (d != NULL) && assign_pages(d, pg, order, memflags) )
{
for ( i = 0; i < (1 << order); i++ )
{
- shadow_drop_references(d, &pg[i]);
- ASSERT((pg[i].u.inuse.type_info & PGT_count_mask) == 0);
- pg[i].tlbflush_timestamp = tlbflush_current_time();
- pg[i].u.free.cpumask = d->domain_dirty_cpumask;
+ BUG_ON((pg[i].u.inuse.type_info & PGT_count_mask) != 0);
list_del(&pg[i].list);
}
*/
for ( i = 0; i < (1 << order); i++ )
{
+ page_set_owner(&pg[i], NULL);
spin_lock(&page_scrub_lock);
list_add(&pg[i].list, &page_scrub_list);
scrub_pages++;
else
{
/* Freeing anonymous domain-heap pages. */
- for ( i = 0; i < (1 << order); i++ )
- cpus_clear(pg[i].u.free.cpumask);
free_heap_pages(pfn_dom_zone_type(page_to_mfn(pg)), pg, order);
drop_dom_ref = 0;
}